package com.relife.sys.controller;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Hashtable;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.relife.common.http.BrowserType;
import com.relife.common.http.BrowserUtils;
import com.relife.common.http.HttpUtil;
import com.relife.common.model.AjaxJson;
import com.relife.common.utils.StringUtil;
import com.relife.common.utils.SysConfig;
import com.relife.core.entity.FileEntity;
import com.relife.sys.service.FileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSONObject;


@Controller
@RequestMapping("sys/file")
@SuppressWarnings("rawtypes")
public class FileController extends BaseController {

	@Autowired
	private FileService fileService;

	/**
	 * 
	 * @author WU
	 * @date 2015年9月6日 下午11:14:17
	 * @param file
	 * @param req
	 * @return
	 * @throws Exception
	 */
	@ResponseBody
	@RequestMapping
	public void uploadFile(FileEntity file, HttpServletRequest req, HttpServletResponse res) {
		JSONObject obj = new JSONObject();
		try {
			String savePath = req.getSession().getServletContext().getRealPath("/");
			fileService.upload(file, savePath);
			String url;
			if (file.isDomain()) {
				url = SysConfig.getProperty("domain_name") + file.getPath();
			} else {
				url = req.getContextPath() + "/" + file.getPath();
			}
			obj.put("id", file.getId());
			obj.put("fileName", file.getName());
			obj.put("error", 0);
			obj.put("url", url);
		} catch (Exception e) {
			e.printStackTrace();
			obj.put("error", 1);
			obj.put("message", e.getMessage() == null ? "上传失败！" : e.getMessage());
		}
		this.write(obj, res);
	}

	/**
	 * 
	 * @author WU
	 * @date 2017年8月8日 上午9:03:21
	 * @param file
	 * @param req
	 * @return
	 */
	@ResponseBody
	@RequestMapping
	public AjaxJson upload(FileEntity file, HttpServletRequest req) {
		AjaxJson j = new AjaxJson();
		try {
			String savePath = req.getSession().getServletContext().getRealPath("/");
			fileService.upload(file, savePath);
		} catch (Exception e) {
			j.setException(e);
			e.printStackTrace();
		}
		return j;
	}

	/**
	 * 删除文件
	 * 
	 * @author WU
	 * @date 2016年8月10日 下午4:12:07
	 * @param id
	 * @return
	 */
	@ResponseBody
	@RequestMapping
	public AjaxJson delFile(String id, String entityName) {
		AjaxJson j = new AjaxJson();
		try {
			fileService.delFile(id, entityName);
		} catch (Exception e) {
			j.setException(e);
			e.printStackTrace();
		}
		return j;
	}

	/**
	 * 文件预览
	 * 
	 * @author WU
	 * @date 2016年8月12日 下午1:46:46
	 * @param req
	 * @param file
	 * @return
	 */
	@RequestMapping
	public String fileView(HttpServletRequest req, FileEntity file) {
		file = fileService.get(FileEntity.class, file.getId());
		req.setAttribute("page", file);
		return "sys/file/fileView";
	}

	/**
	 * 
	 * @author WU
	 * @date 2016年8月12日 下午3:21:20
	 * @param res
	 * @param file
	 * @param req
	 * @throws Exception
	 */
	@SuppressWarnings("resource")
	@RequestMapping
	public void ieFileView(HttpServletResponse res, FileEntity file, HttpServletRequest req) throws Exception {
		file = fileService.get(FileEntity.class, file.getId());
		String savePath = req.getSession().getServletContext().getRealPath("/");
		InputStream in = new FileInputStream(savePath + file.getPath());
		byte[] b = new byte[1024];
		int len = -1;

		while ((len = in.read(b, 0, 1024)) != -1) {
			res.getOutputStream().write(b, 0, len);
		}
		res.addHeader("Accept-Language", "zh-tw");
		res.setContentType("application/octet-stream");
	}

	/**
	 * 
	 * @author WU
	 * @date 2015年9月9日 下午5:00:31
	 * @param req
	 * @param res
	 */
	@SuppressWarnings("unchecked")
	@RequestMapping("/fileManager")
	public void fileManager(HttpServletRequest req, HttpServletResponse res) {
		// 根目录路径，可以指定绝对路径，比如 /var/www/attached/
		String rootPath = req.getServletContext().getRealPath("/") + "upload/";
		// 根目录URL，可以指定绝对路径，比如 http://www.yoursite.com/attached/
		String rootUrl = SysConfig.getProperty("domain_name") + "upload/";
		// 图片扩展名
		String[] fileTypes = new String[] { "gif", "jpg", "jpeg", "png", "bmp" };

		// 根据path参数，设置各路径和URL
		String path = req.getParameter("path") != null ? req.getParameter("path") : "";
		String currentPath = rootPath + path;
		String currentUrl = rootUrl + path;
		String currentDirPath = path;
		String moveupDirPath = "";
		if (!"".equals(path)) {
			String str = currentDirPath.substring(0, currentDirPath.length() - 1);
			moveupDirPath = str.lastIndexOf("/") >= 0 ? str.substring(0, str.lastIndexOf("/") + 1) : "";
		}

		// 排序形式，name or size or type
		String order = req.getParameter("order") != null ? req.getParameter("order").toLowerCase() : "name";

		// 不允许使用..移动到上一级目录
		if (path.indexOf("..") >= 0) {
			this.write("Access is not allowed.", res);
			return;
		}
		// 最后一个字符不是/
		if (!"".equals(path) && !path.endsWith("/")) {
			this.write("Parameter is not valid.", res);
			return;
		}
		// 目录不存在或不是目录
		File currentPathFile = new File(currentPath);
		if (!currentPathFile.isDirectory()) {
			this.write("Directory does not exist.", res);
			return;
		}

		// 遍历目录取的文件信息
		List<Hashtable> fileList = new ArrayList<Hashtable>();
		if (currentPathFile.listFiles() != null) {
			for (File file : currentPathFile.listFiles()) {
				Hashtable<String, Object> hash = new Hashtable<String, Object>();
				String fileName = file.getName();
				if (file.isDirectory()) {
					hash.put("is_dir", true);
					hash.put("has_file", (file.listFiles() != null));
					hash.put("filesize", 0L);
					hash.put("is_photo", false);
					hash.put("filetype", "");
				} else if (file.isFile()) {
					String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
					hash.put("is_dir", false);
					hash.put("has_file", false);
					hash.put("filesize", file.length());
					hash.put("is_photo", Arrays.<String> asList(fileTypes).contains(fileExt));
					hash.put("filetype", fileExt);
				}
				hash.put("filename", fileName);
				hash.put("datetime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(file.lastModified()));
				fileList.add(hash);
			}
		}

		if ("size".equals(order)) {
			Collections.sort(fileList, new SizeComparator());
		} else if ("type".equals(order)) {
			Collections.sort(fileList, new TypeComparator());
		} else {
			Collections.sort(fileList, new NameComparator());
		}
		JSONObject result = new JSONObject();
		result.put("moveup_dir_path", moveupDirPath);
		result.put("current_dir_path", currentDirPath);
		result.put("current_url", currentUrl);
		result.put("total_count", fileList.size());
		result.put("file_list", fileList);
		this.write(result, res);
	}

	public class NameComparator implements Comparator {
		public int compare(Object a, Object b) {
			Hashtable hashA = (Hashtable) a;
			Hashtable hashB = (Hashtable) b;
			if (((Boolean) hashA.get("is_dir")) && !((Boolean) hashB.get("is_dir"))) {
				return -1;
			} else if (!((Boolean) hashA.get("is_dir")) && ((Boolean) hashB.get("is_dir"))) {
				return 1;
			} else {
				return ((String) hashA.get("filename")).compareTo((String) hashB.get("filename"));
			}
		}
	}

	public class SizeComparator implements Comparator {
		public int compare(Object a, Object b) {
			Hashtable hashA = (Hashtable) a;
			Hashtable hashB = (Hashtable) b;
			if (((Boolean) hashA.get("is_dir")) && !((Boolean) hashB.get("is_dir"))) {
				return -1;
			} else if (!((Boolean) hashA.get("is_dir")) && ((Boolean) hashB.get("is_dir"))) {
				return 1;
			} else {
				if (((Long) hashA.get("filesize")) > ((Long) hashB.get("filesize"))) {
					return 1;
				} else if (((Long) hashA.get("filesize")) < ((Long) hashB.get("filesize"))) {
					return -1;
				} else {
					return 0;
				}
			}
		}
	}

	public class TypeComparator implements Comparator {
		public int compare(Object a, Object b) {
			Hashtable hashA = (Hashtable) a;
			Hashtable hashB = (Hashtable) b;
			if (((Boolean) hashA.get("is_dir")) && !((Boolean) hashB.get("is_dir"))) {
				return -1;
			} else if (!((Boolean) hashA.get("is_dir")) && ((Boolean) hashB.get("is_dir"))) {
				return 1;
			} else {
				return ((String) hashA.get("filetype")).compareTo((String) hashB.get("filetype"));
			}
		}
	}

	@ResponseBody
	@RequestMapping
	public void downFile(String id, HttpServletRequest req, HttpServletResponse response, boolean isOnLine) throws Exception {
		BrowserType type = BrowserUtils.getBrowserType(HttpUtil.getRequest());
		
		String filePath = "";
		FileEntity file = new FileEntity();
		if (StringUtil.isNotEmpty(id)) {
			file = service.get(FileEntity.class, id);
			if (file != null) {
				filePath = file.getPath();
			}
		}
		String fileHome = req.getSession().getServletContext().getRealPath("/");
		File f = new File(fileHome + "\\" + filePath);
		if (!f.exists()) {
			response.sendError(404, "文件没找到或已被删除!");
			return;
		}
		isOnLine = false;
		BufferedInputStream br = new BufferedInputStream(new FileInputStream(f));
		byte[] buf = new byte[1024];
		int len = 0;

		response.reset(); // 非常重要
		if (isOnLine) { // 在线打开方式
			URL u = new URL("file:///" + filePath);
			response.setContentType(u.openConnection().getContentType());
			response.setHeader("Content-Disposition", "inline; filename=" + f.getName());
			// 文件名应该编码成UTF-8
		} else { // 纯下载方式
			response.setContentType("UTF-8");
			response.setCharacterEncoding("UTF-8");
			if (file.getSuffix().equals("text")) {
				response.setContentType("text/plain;");
			} else if (file.getSuffix().equals("doc") || file.getSuffix().equals("docx")) {
				if( BrowserType.Safari.equals(type)){
					response.setContentType("applicatoin/octet-stream;");					
				}else{
					response.setContentType("application/msword;");
				}
			} else if (file.getSuffix().equals("xls") || file.getSuffix().equals("xlsx")) {
				if( BrowserType.Safari.equals(type)){
					response.setContentType("applicatoin/octet-stream;");					
				}else{
					response.setContentType("application/ms-excel;");
				}
			} else if (file.getSuffix().equals("pdf")) {
				response.setContentType("application/pdf;");
			} else if (file.getSuffix().equals("jpg") || file.getSuffix().equals("jpeg")) {
				response.setContentType("image/jpeg;");
			} else {
				if( BrowserType.Safari.equals(type)){
					response.setContentType("applicatoin/octet-stream;");					
				}else{
					response.setContentType("application/x-msdownload;");
				}
			}
			response.setHeader("Content-Disposition", "attachment; filename=" + f.getName());
			response.setHeader("Content-Length", String.valueOf(file.getFileSize()));
		}
		OutputStream out = response.getOutputStream();
		while ((len = br.read(buf)) > 0)
			out.write(buf, 0, len);
		br.close();
		out.close();
	}
}
